package com.xyrl.project.common.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xyrl.common.base.exception.XyrlException;
import com.xyrl.common.util.ObjectUtil;
import com.xyrl.common.util.domain.QueryRequest;
import com.xyrl.project.common.base.service.CacheService;
import com.xyrl.project.common.common.enu.AttImageUseType;
import com.xyrl.project.common.common.service.AttachmentService;
import com.xyrl.project.common.constant.XyrlConstant;
import com.xyrl.project.common.manager.UserManager;
import com.xyrl.project.common.system.dao.UserMapper;
import com.xyrl.project.common.system.dao.UserRoleMapper;
import com.xyrl.project.common.system.entity.User;
import com.xyrl.project.common.system.entity.UserRole;
import com.xyrl.project.common.system.service.UserConfigService;
import com.xyrl.project.common.system.service.UserRoleService;
import com.xyrl.project.common.system.service.UserService;
import com.xyrl.project.common.util.MD5Util;
import com.xyrl.project.common.util.SortUtil;
import com.xyrl.starter.lock.redis.lock.DistributedLock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Date;

@Slf4j
@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private UserConfigService userConfigService;
    @Autowired
    private CacheService cacheService;
    @Autowired
    private UserRoleService userRoleService;
    @Autowired
    private UserManager userManager;

    @Autowired
    private DistributedLock distributedLock;
    @Autowired
    private AttachmentService attachmentService;


    @Override
    public User findByName(String username) {
        return baseMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getAccount, username).eq(User::getIsDelete, XyrlConstant.NO));
    }

    @Override
    public User findAndCacheByName(String userName) {
        User user = findByName(userName);
        try {
            cacheService.saveUser(user);
        } catch (Exception e) {
            log.error("缓存登录用户失败", e);
        }
        return user;
    }

    @Override
    public IPage<User> findUserDetail(User user, QueryRequest request) {
        try {
            Page<User> page = new Page<>();
            SortUtil.handlePageSort(request, page, "userId", XyrlConstant.ORDER_ASC, false);
            return this.baseMapper.findUserDetail(page, user);
        } catch (Exception e) {
            log.error("查询用户异常", e);
            return null;
        }
    }

    @Override
    @Transactional
    public void updateLoginTime(String username) throws Exception {
        User user = new User();
        user.setLastLoginTime(new Date());
        this.baseMapper.update(user, new LambdaQueryWrapper<User>().eq(User::getAccount, username));
        // 重新将用户信息加载到 redis中
        cacheService.saveUser(username);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createUser(User user) throws Exception {
        boolean isLock = distributedLock.lockWithoutWaiting(XyrlConstant.LOCK_CREATE_USER_SIGN_KEY);
        if (!isLock) {
            throw new XyrlException("正在添加用户，请稍后再试");
        }
        try {
            if (haveAccount(user.getAccount(), user.getMobile())) {
                throw new XyrlException("帐号或手机号己存在");
            }
            // 创建用户
            user.setCreateTime(new Date());
            if (ObjectUtil.isEmpty(user.getAvatar())) {
                user.setAvatar(User.DEFAULT_AVATAR);
            }
            user.setPassword(MD5Util.encrypt(user.getAccount(), User.DEFAULT_PASSWORD));
            user.setIsDelete(XyrlConstant.NO);
            save(user);
            /**
             * 添加客户经理时 用户未设置角色
             */
            if (ObjectUtil.isNotEmpty(user.getRoleId())) {
                // 保存用户角色
                String[] roles = user.getRoleId().split(StringPool.COMMA);
                setUserRoles(user, roles);
            }
            // 创建用户默认的个性化配置
            userConfigService.initDefaultUserConfig(String.valueOf(user.getUserId()));
            // 将用户相关信息保存到 Redis中
            userManager.loadUserRedisCache(user);
            //设置附件
            if(ObjectUtil.isNotEmpty(user.getAttId())){
                attachmentService.handleAttImageUseAttId(user.getUserId(), AttImageUseType.salesMainLogo,user.getAttId());
            }
        } finally {
            distributedLock.releaseLock(XyrlConstant.LOCK_CREATE_USER_SIGN_KEY);
        }
    }

    /**
     * 校验登录帐号或手机号是否己存在
     *
     * @param userName
     * @author zhongp
     * @date 2019-12-27 10:09:29
     */
    private boolean haveAccount(String userName) {
        return haveAccount(userName, null);
    }

    /**
     * 校验登录帐号或手机号是否己存在
     *
     * @param userName
     * @param mobile
     * @author zhongp
     * @date 2019-12-27 10:09:29
     */
    private boolean haveAccount(String userName, String mobile) {
        QueryWrapper<User> wrapper = new QueryWrapper<User>();
        wrapper.eq("is_delete", XyrlConstant.NO);
        wrapper.lambda().and(search -> search.eq(User::getAccount, userName).or().eq(User::getMobile, mobile));
        int total = baseMapper.selectCount(wrapper);
        //判断统计数量是否大于零 如果 大于零说明己存在帐号
        if (total > 0) {
            return true;
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(User user) throws Exception {
        User oldUser = getById(user.getId());

        String head = oldUser.getAvatar();
        // 更新用户
        user.setPassword(null);
        user.setModifyTime(new Date());
        updateById(user);
        //判断是否做过头像变更 老用户的头像与修改用户头像不一至
        attachmentService.changeImageUsePath(user.getUserId(),AttImageUseType.salesMainLogo,user.getAvatar(),head);

        userRoleMapper.delete(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, user.getUserId()));
        if (ObjectUtil.isNotEmpty(user.getRoleId())) {
            String[] roles = user.getRoleId().split(StringPool.COMMA);
            setUserRoles(user, roles);
        }
        // 重新将用户信息，用户角色信息，用户权限信息 加载到 redis中
        cacheService.saveUser(user.getAccount());
        cacheService.saveRoles(user.getAccount());
        cacheService.savePermissions(user.getAccount());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteUsers(String[] userIds) throws Exception {
        // 先删除相应的缓存
        this.userManager.deleteUserRedisCache(userIds);
        User user = new User();
        user.setIsDelete(XyrlConstant.YES);
        user.setModifyTime(new Date());
        UpdateWrapper<User> up = new UpdateWrapper<User>();
        up.lambda().and(where -> where.in(User::getUserId, userIds));
        int total = baseMapper.update(user, up);
    }

    @Override
    @Transactional
    public void updateProfile(User user) throws Exception {
        updateById(user);
        // 重新缓存用户信息
        cacheService.saveUser(user.getAccount());
    }

    @Override
    @Transactional
    public void updateAvatar(String username, String avatar) throws Exception {
        User user = new User();
        user.setAvatar(avatar);
        this.baseMapper.update(user, new LambdaQueryWrapper<User>().eq(User::getAccount, username));
        // 重新缓存用户信息
        cacheService.saveUser(username);
    }

    @Override
    @Transactional
    public void updatePassword(String username, String password) throws Exception {
        User user = new User();
        user.setPassword(MD5Util.encrypt(username, password));

        this.baseMapper.update(user, new LambdaQueryWrapper<User>().eq(User::getAccount, username));
        // 重新缓存用户信息
        cacheService.saveUser(username);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void regist(String username, String password) throws Exception {
        boolean isLock = distributedLock.lockWithoutWaiting(XyrlConstant.LOCK_CREATE_USER_SIGN_KEY);
        if (!isLock) {
            throw new XyrlException("正在添加用户，请稍后再试");
        }
        try {
            if (haveAccount(username)) {
                throw new XyrlException("帐号己存在");
            }
            User user = new User();
            user.setPassword(MD5Util.encrypt(username, password));
            user.setAccount(username);
            user.setCreateTime(new Date());
            user.setStatus(User.STATUS_VALID);
            user.setSsex(User.SEX_UNKNOW);
            user.setAvatar(User.DEFAULT_AVATAR);
            user.setDescription("注册用户");
            this.save(user);

            UserRole ur = new UserRole();
            ur.setUserId(user.getUserId());
            ur.setRoleId(2L); // 注册用户角色 ID
            this.userRoleMapper.insert(ur);
            // 创建用户默认的个性化配置
            userConfigService.initDefaultUserConfig(String.valueOf(user.getUserId()));
            // 将用户相关信息保存到 Redis中
            userManager.loadUserRedisCache(user);

        } finally {
            distributedLock.releaseLock(XyrlConstant.LOCK_CREATE_USER_SIGN_KEY);
        }
    }

    @Override
    @Transactional
    public void resetPassword(String[] usernames) throws Exception {
        for (String username : usernames) {
            User user = new User();
            user.setPassword(MD5Util.encrypt(username, User.DEFAULT_PASSWORD));
            this.baseMapper.update(user, new LambdaQueryWrapper<User>().eq(User::getAccount, username));
            // 重新将用户信息加载到 redis中
            cacheService.saveUser(username);
        }

    }

    private void setUserRoles(User user, String[] roles) {
        Arrays.stream(roles).forEach(roleId -> {
            UserRole ur = new UserRole();
            ur.setUserId(user.getUserId());
            ur.setRoleId(Long.valueOf(roleId));
            this.userRoleMapper.insert(ur);
        });
    }
}
